﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LEVUtilityLibrary
{
    public class B2BToolKit_USBPacketFormat
    {
        private const byte LeadingCode = 0x3A;   //起始字元
        private const byte SlaveAddressCode = 0xA6;    //Slave Address
        private const byte EndingCode1 = 0x0D;//結束字元 1
        private const byte EndingCode2 = 0x0A; //結束字元 2

        private const int Transmitting_Max_Data_Length_PcToUSB = (0x1f);  //not whole structure Length, only Data buffer Length
        private const int Receiving_Max_Data_Length_UsbToPc = 512;//(0xff);   //not whole structure Length, only Data buffer Length
        /*  USB_CDC_Transmit_Packet
        struct USB_CDC_Transmit_Packet
        {
            private const byte LeadingCode = CDC_LeadingCode;   //起始字元
            private const byte SlAdd = CDC_SlaveAddressCode;    //Slave Address
            public byte command;    //命令
            private byte DataLenExpected_low;//數據長度, 
            private byte DataLenExpected_high;//數據長度,
            [MarshalAs(UnmanagedType.ByValArray, SizeConst=CDC_Transmitting_Max_Data_Length)]
            private byte[] DataBuf;//數據內容
            private byte LRCDataLow;           //checkSum16 Low byte, included slave address, command, length and data.
            private byte LRCDataHigh;	      //checkSum16 High byte, included slave address, command, length and data.
            private const byte cEND1 = CDC_EndingCode1;//結束字元 1
            private const byte cEND2 = CDC_EndingCode2;//結束字元 2
        }*/
        public static byte[] Packing(byte TransmittedCmd, byte[] TransmittedParameter)
        {
            byte[] TempData;
            List<byte> TransmitData = new List<byte>();
            UInt16 LenExpected;
            //if (TransmittedCmd == 0x92)
            //{
            //    LenExpected = 0;
            //}

            if (TransmittedParameter.Length > Transmitting_Max_Data_Length_PcToUSB)
            {
                throw new Exception("The size of Transmitted Parameter must be less than or equal to " + Transmitting_Max_Data_Length_PcToUSB);
                //LenExpected = Transmitting_Max_Data_Length_PcToUSB;
                //TempData = new byte[LenExpected];
                //for (UInt16 i = 0; i < LenExpected; i++)
                //{
                //    TempData[i] = Transmit_Parameter[i];
                //}
            }
            else
            {
                LenExpected = (UInt16)TransmittedParameter.Length;
                TempData = (byte[])TransmittedParameter.Clone();
            }

            TransmitData.Add(SlaveAddressCode);
            TransmitData.Add(TransmittedCmd);
            TransmitData.Add((byte)LenExpected);
            TransmitData.Add((byte)(LenExpected >> 8));
            TransmitData.AddRange(TempData);


            byte[] CheckBuffer = TransmitData.ToArray<Byte>();
            ushort checkSum = MassUtilities.ComputeCheckSum16(CheckBuffer);

            TransmitData.Add((byte)(checkSum));           // low byte     //4 to last byte for packet
            TransmitData.Add((byte)(checkSum >> 8));      // high byte    //3 to last byte for packet
            TransmitData.Add(EndingCode1);                //2 to last byte for packet
            TransmitData.Add(EndingCode2);                //last byte for packet

            TransmitData.Insert(0, LeadingCode);        // add first Item

            return TransmitData.ToArray<Byte>();
        }

        /*   USB_CDC_Receiving_Packet
         struct USB_CDC_Receiving_Packet
         {
             private const byte LeadingCode = CDC_LeadingCode;   //起始字元
             private const byte SlAdd = CDC_SlaveAddressCode;    //Slave Address
             public byte command;    //命令
            private byte DataLenExpected_low;//數據長度, 
            private byte DataLenExpected_high;//數據長度,
         * [MarshalAs(UnmanagedType.ByValArray, SizeConst=CDC_Receiving_Max_Data_Length)]
             public byte[] DataBuf;//數據內容
             public byte LRCDataLow;           //checkSum16 Low byte, included slave address, command, length and data.
             public byte LRCDataHigh;	      //checkSum16 High byte, included slave address, command, length and data.
             private const byte cEND1 = CDC_EndingCode1;//結束字元 1
             private const byte cEND2 = CDC_EndingCode2;//結束字元 2
         }*/
        public static bool Unpacking(byte[] ReceivedRawData, out byte ReceivedCommand, out byte[] ReceivedParameter)
        {
            int segStartIdxOfRawData = 0;
            int segEndIdxOfRawData = 0;
            return Unpacking(ReceivedRawData, out ReceivedCommand, out ReceivedParameter, out segStartIdxOfRawData, out segEndIdxOfRawData);
        }
        public static bool Unpacking(byte[] ReceivedRawData, out byte ReceivedCommand, out byte[] ReceivedParameter, out int segStartIdxOfRawData, out int segEndIdxOfRawData)
        {
            bool IsFound_Packet_Form = false;
            segStartIdxOfRawData = 0;
            segEndIdxOfRawData = 0;
            ReceivedCommand = 0;
            ReceivedParameter = new byte[0];
            List<byte> ReceivedDataList = new List<byte>();

            int startFormIndex;
            int dataLength, endCode1_idx, endCode2_idx;
            if (ReceivedRawData.Length < 2)
            {
                return IsFound_Packet_Form;
            }
            for (int i = 0; i < (ReceivedRawData.Length - 1); i++)
            {
                //finding leading codes
                if ((ReceivedRawData[i] == LeadingCode) && (ReceivedRawData[i + 1] == SlaveAddressCode))
                {
                    startFormIndex = i;
                    if ((startFormIndex + 4) >= ReceivedRawData.Length)
                    {
                        return IsFound_Packet_Form;
                    }

                    dataLength = (ReceivedRawData[startFormIndex + 4] << 8) + ReceivedRawData[startFormIndex + 3];    //offset 3 to get receiving data length low, offset 4 to get receiving data length high
                    endCode1_idx = startFormIndex + 4 + dataLength + 2 + 1;  //add offset 2 is two of Cuecksum bytes
                    endCode2_idx = startFormIndex + 4 + dataLength + 2 + 2;  //add offset 2 is two of Cuecksum bytes
                    if (endCode2_idx >= ReceivedRawData.Length)
                    {
                        return IsFound_Packet_Form;
                    }
                    //finding Ending Codes
                    if ((ReceivedRawData[endCode1_idx] == EndingCode1) && (ReceivedRawData[endCode2_idx] == EndingCode2))
                    {
                        //calculate checkSum
                        byte[] CheckBuffer = new byte[dataLength + 4]; //included slave address, command, length and data.
                        Array.Copy(ReceivedRawData, startFormIndex + 1, CheckBuffer, 0, CheckBuffer.Length);
                        ushort checkSum = MassUtilities.ComputeCheckSum16(CheckBuffer);
                        int checkSumLowByte_Index = endCode1_idx - 2;
                        int checkSumHighByte_Index = checkSumLowByte_Index + 1;
                        if (ReceivedRawData[checkSumLowByte_Index] == ((byte)(checkSum)) && ReceivedRawData[checkSumHighByte_Index] == ((byte)(checkSum >> 8)))
                        {
                            //Save data to structure
                            ReceivedCommand = ReceivedRawData[startFormIndex + 2];

                            for (int j = 0; j < dataLength; j++)
                            {
                                ReceivedDataList.Add(ReceivedRawData[startFormIndex + 5 + j]);
                            }
                            segStartIdxOfRawData = startFormIndex;
                            segEndIdxOfRawData = startFormIndex + 5 + dataLength - 1;
                            IsFound_Packet_Form = true;
                            break;
                        }
                    }//if((ReceivingData[endCode1_idx] == EndingCode1) && (ReceivingData[endCode2_idx] == EndingCode2)){
                }//if((ReceivingData[i] == LeadingCode) && (ReceivingData[i+1] == SlaveAddressCode)){
            }//for(int i = 0; i < (ReceivingData.Length - 1); i++){
            if (IsFound_Packet_Form)
            {
                ReceivedParameter = ReceivedDataList.ToArray<byte>();
            }
            return IsFound_Packet_Form;
        }
    }//public class B2BToolKit_USBPacketFormat
}//public class B2BToolKit_USBPacketFormat
